/*
 * SyntacticParser.c
 * VB Script Analyzer
 * @author Gregoire JACOB (gregoire.jacob@orange-ftgroup.com)
 * @date 27/08/2008
 * @version 1.1
 * Analyse the syntax of the script in order to recover the different
 * procedures, functions, their arguments, managers and variables
 */

#include ".\Includes\Analyzer.h"


int detectStringCiphering(struct SCRIPT * script, struct TYPING * types,
						   unsigned long location, int lineindex, FILE * scriptf){
	struct LINE * code;
	int i, nb, findex = -1, nbarg, nbline;
	char tokens[TOKENMAXNB][TOKENSIZE];
	char variable[TOKENSIZE];
	char * found = NULL;
	FILE * decroutine;
	long position = 0L, size = 0L; int isciphered = 0;
	
	code = accessLine(script,location,lineindex);
	found = strcasestr(code->line,OBJECT_CREATION);
	if(found==NULL) return 0;
	nb = decomposeLine(found,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	if(nb<2) return 0;
	//Ciphering imbricated in the call
	findex = isLocalFunction(script,tokens[1]);
	if(findex>=0){ //String ciphered
		isciphered = 1;
		script->cipherfunction = findex;
	}
	//Intermediate ciphered variable
	strcpy_s(variable,TOKENSIZE,tokens[1]);
	if(variable[0]=='"') return 0;
	//Search variable initialization
	for(i=0;i<lineindex;i++){
		code = accessLine(script,location,i);
		found = strcasestr(code->line,variable);
		if(found==NULL) continue;
			nb = decomposeLine(found,(char*)tokens,TOKENMAXNB,TOKENSIZE);
			if(nb<2||tokens[1][0]!='=') continue;
			findex = isLocalFunction(script,tokens[2]);
			if(findex>=0){ //String ciphered
				isciphered = 1;
				script->cipherfunction = findex;
			}//Ciphered
	}
	if(!isciphered) return 0;

	//Building deciphering script
	position = ftell(scriptf);
	parseFunction(script->cipherfunction,script,types,scriptf);
	nbarg = script->functionslist[script->cipherfunction].nbarg;
	nbline = script->functionslist[script->cipherfunction].nblines;
	strcat_s(script->cipherscript,NAME_MAX_LENGTH,script->name);
	script->cipherscript[strlen(script->cipherscript)-3]=0;
	strcat_s(script->cipherscript,NAME_MAX_LENGTH,"decscript.vbs");
	fopen_s(&decroutine,script->cipherscript,"wt");
	//fprintf(decroutine,"#! C:\\WINDOWS\\system32\\cscript.exe\n"); 
	fprintf(decroutine,"dim objFSO, objFile\n");
	fprintf(decroutine,"Set args  = Wscript.Arguments\n");
	fprintf(decroutine,"Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n");
	fprintf(decroutine,"Set objFile = objFSO.CreateTextFile(\"deciphered.txt\",True,False)\n");
	fprintf(decroutine,"objFile.Writeline(%s(",
		script->functionslist[script->cipherfunction].name);
	if(nbarg) fprintf(decroutine,"args(0)");
	for(i=1;i<nbarg;i++){
		fprintf(decroutine,",args(%d)",i);
	}
	fprintf(decroutine,"))\n");
	fprintf(decroutine,"Wscript.quit\n\n");

	fprintf(decroutine,"Function %s(",
		script->functionslist[script->cipherfunction].name);
	if(nbarg) fprintf(decroutine,"%s",
		script->functionslist[script->cipherfunction].arguments[0]);
	for(i=1;i<nbarg;i++){
		fprintf(decroutine,",%s",
		script->functionslist[script->cipherfunction].arguments[i]);
	}
	fprintf(decroutine,")\n");
	size = script->functionslist[script->cipherfunction].end - 
		script->functionslist[script->cipherfunction].codepos;
	fseek(scriptf,script->functionslist[script->cipherfunction].codepos,SEEK_SET);
	found = calloc(size,1);
	fread(found,1,size,scriptf);
	fwrite(found,1,size,decroutine);
	fprintf(decroutine,"\n");
	fflush(decroutine);
	fclose(decroutine);
	// /!\Must be set after parsing deciphering function
	// to avoid possible recursion (return affectation for example)
	fseek(scriptf,position,SEEK_SET);
	script->strciphered = 1;
	return 1;
}

void decipherString(struct SCRIPT * script, char * call, int nbargs){
	FILE * deciphered = NULL;
	char tokens[TOKENMAXNB][TOKENSIZE]; int nbtokens;
	char command[LINE_LENGTH];
	char deciph[NAME_MAX_LENGTH];
	char * next; char endline[LINE_LENGTH*2];
	int i; errno_t err;
	
	//Deciphering routine
	nbtokens = decomposeLine(call,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	if (nbtokens < nbargs) return;
	sprintf_s(command,LINE_LENGTH,
			  "C:\\WINDOWS\\system32\\cscript.exe //B \"%s\" ", script->cipherscript);
	for(i=0; i<nbargs; i++){
		strcat_s(command,LINE_LENGTH," ");
		strcat_s(command,LINE_LENGTH,tokens[i+1]);
	}
	strcat_s(command,LINE_LENGTH,"\n");
	//printf("%s",command);
	system(command);  
	err = fopen_s(&deciphered,"deciphered.txt","rt");
	if(deciphered) fgets(deciph,NAME_MAX_LENGTH,deciphered);
	if(deciph[strlen(deciph)-1]=='\n') deciph[strlen(deciph)-1] = 0;
	if(deciphered) fclose(deciphered);
	
	//Rebuild deciphered line
	next = call;
	while(*next!=0){
		next++;
		if(!strncmp(next,tokens[i],strlen(tokens[i]))) break;
	}
	next+=strlen(tokens[i])+1;
	*call = 0;
	strcpy_s(endline,LINE_LENGTH*2,next);
	strcat_s(call,LINE_LENGTH,"\"");
	strcat_s(call,LINE_LENGTH,deciph);
	strcat_s(call,LINE_LENGTH,"\"");
	strcat_s(call,LINE_LENGTH,endline);

	next = strstr(call,script->functionslist[script->cipherfunction].name);
	if(next) decipherString(script,next,nbargs);
}

int extractFileSystemObject(struct MANAG_ENTRY * managers, struct LINE * line){
	char * fsofound = 0;
	char * createfound = 0;
	char * commentfound = 0;
	char tokens[TOKENMAXNB][TOKENSIZE];
	int i, nbtokens;
	//Looking for file system object
	commentfound = strcasestr(line->line," '");
	if(commentfound) *commentfound = 0;
	fsofound = strcasestr(line->line,FSO_NAME);
	if(fsofound==NULL){//Looking for an other alias
		for(i=0;i<managers->nbfsoalias;i++){
			fsofound = strcasestr(line->line,managers->FileSystemAliases[i]);
			if (fsofound!=NULL) break;
		}
	}
	if(fsofound==NULL) return 0;//No reference to fso has been found

	//Otherwise line refering to a manager, update script stucture
	line->type = MANAGER;
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	createfound = strcasestr(line->line,OBJECT_CREATION);
	if(createfound==NULL) createfound = strcasestr(line->line,OBJECT_CREATION2);
	if(createfound==NULL){//new alias
		if(!strcmp(tokens[1],"=")){//&&nbtokens<=3){
			addManagerAlias(managers,TFSO,tokens[0]);//direct affectation
			return 1;
		}else if(strcmp(tokens[2],"=")){//&&nbtokens<=4){
			addManagerAlias(managers,TFSO,tokens[1]);//variable type in first position
			return 1;
		}
	}else if(nbtokens>=4){//new object
		if(!strcmp(tokens[2],"=")){
			if(!strcasecmp(tokens[3],"WScript")&&
				!strcasecmp(tokens[4],"CreateObject")){
				addManagerObject(managers,TFSO,tokens[1]);
				return 1;
			}else if(!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TFSO,tokens[1]);
				return 1;
			}else if(!strcasecmp(tokens[3],"new")&&
				!strcasecmp(tokens[4],"ActiveXObject")){
				addManagerObject(managers,TFSO,tokens[1]);
				return 1;
			}
		}else if(!strcmp(tokens[1],"=")){
			if(!strcasecmp(tokens[2],"WScript")&&
				!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TFSO,tokens[0]);
				return 1;
			}else if(!strcasecmp(tokens[2],"CreateObject")){
				addManagerObject(managers,TFSO,tokens[0]);
				return 1;
			}else if(!strcasecmp(tokens[2],"new")&&
				!strcasecmp(tokens[3],"ActiveXObject")){
				addManagerObject(managers,TFSO,tokens[0]);
				return 1;
			}
		}
	}
	return 0;
}

int extractShellObject(struct MANAG_ENTRY * managers, struct LINE * line){
	char * shellfound = 0;
	char * createfound = 0;
	char * commentfound = 0;
	char tokens[TOKENMAXNB][TOKENSIZE];
	int i, nbtokens;
	//Looking for shell object
	commentfound = strcasestr(line->line," '");
	if(commentfound) *commentfound = 0;
	shellfound = strcasestr(line->line,SHELL_NAME);
	if(shellfound==NULL){//Looking for an other alias
		for(i=0;i<managers->nbshellalias;i++){
			shellfound = strcasestr(line->line,managers->ShellAliases[i]);
			if (shellfound!=NULL) break;
		}
	}
	if(shellfound==NULL) return 0;//No reference to shell has been found

	//Otherwise line refering to a manager, update script stucture
	line->type = MANAGER;
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	createfound = strcasestr(line->line,OBJECT_CREATION);
	if(createfound==NULL){//new alias
		if(!strcmp(tokens[1],"=")){
			addManagerAlias(managers,TSHELL,tokens[0]);//direct affectation
			return 1;
		}else if(strcmp(tokens[2],"=")){
			addManagerAlias(managers,TSHELL,tokens[1]);//variable type in first position
			return 1;
		}
	}else if(nbtokens>=4){//new object
		if(!strcmp(tokens[2],"=")){
			if(!strcasecmp(tokens[3],"WScript")&&
				!strcasecmp(tokens[4],"CreateObject")){
				addManagerObject(managers,TSHELL,tokens[1]);
				return 1;
			}else if(!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TSHELL,tokens[1]);
				return 1;
			}
		}else if(!strcmp(tokens[1],"=")){
			if(!strcasecmp(tokens[2],"WScript")&&
				!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TSHELL,tokens[0]);
				return 1;
			}else if(!strcasecmp(tokens[2],"CreateObject")){
				addManagerObject(managers,TSHELL,tokens[0]);
				return 1;
			}
		}
	}
	return 0;
}

int extractNetworkObject(struct MANAG_ENTRY * managers, struct LINE * line){
	char * netfound = 0;
	char * createfound = 0;
	char * commentfound = 0;
	char tokens[TOKENMAXNB][TOKENSIZE];
	int i, nbtokens;
	//Looking for network object
	commentfound = strcasestr(line->line," '");
	if(commentfound) *commentfound = 0;
	netfound = strcasestr(line->line,NET_NAME);
	if(netfound==NULL){//Looking for an other alias
		for(i=0;i<managers->nbnetalias;i++){
			netfound = strcasestr(line->line,managers->NetworkAliases[i]);
			if (netfound!=NULL) break;
		}
	}
	if(netfound==NULL) return 0;//No reference to network has been found

	//Otherwise line refering to a manager, update script stucture
	line->type = MANAGER;
	nbtokens = decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	createfound = strcasestr(line->line,OBJECT_CREATION);
	if(createfound==NULL){//new alias
		if(!strcmp(tokens[1],"=")){
			addManagerAlias(managers,TNETW,tokens[0]);//direct affectation
			return 1;
		}else if(strcmp(tokens[2],"=")){
			addManagerAlias(managers,TNETW,tokens[1]);//variable type in first position
			return 1;
		}
	}else if(nbtokens>=4){//new object
		if(!strcmp(tokens[2],"=")){
			if(!strcasecmp(tokens[3],"WScript")&&
				!strcasecmp(tokens[4],"CreateObject")){
				addManagerObject(managers,TNETW,tokens[1]);
				return 1;
			}else if(!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TNETW,tokens[1]);
				return 1;
			}
		}else if(!strcmp(tokens[1],"=")){
			if(!strcasecmp(tokens[2],"WScript")&&
				!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TNETW,tokens[0]);
				return 1;
			}else if(!strcasecmp(tokens[2],"CreateObject")){
				addManagerObject(managers,TNETW,tokens[0]);
				return 1;
			}
		}
	}
	return 0;
}

int extractMailObject(struct MANAG_ENTRY * managers, struct LINE * line){
	char * mailfound = 0;
	char * createfound = 0;
	char * commentfound = 0;
	char tokens[TOKENMAXNB][TOKENSIZE];
	int i, nbtokens;
	//Looking for mail object
	commentfound = strcasestr(line->line," '");
	if(commentfound) *commentfound = 0;
	mailfound = strcasestr(line->line,MAIL_NAME);
	if(mailfound==NULL){//Looking for an other alias
		for(i=0;i<managers->nbmailalias;i++){
			mailfound = strcasestr(line->line,managers->MailAliases[i]);
			if (mailfound!=NULL) break;
		}
	}
	if(mailfound==NULL) return 0;//No reference to network has been found

	//Otherwise line refering to a manager, update script stucture
	line->type = MANAGER;
	nbtokens=decomposeLine(line->line,(char*)tokens,TOKENMAXNB,TOKENSIZE);
	createfound = strcasestr(line->line,OBJECT_CREATION);
	if(createfound==NULL){//new alias
		if(!strcmp(tokens[1],"=")){
			addManagerAlias(managers,TMAIL,tokens[0]);//direct affectation
			return 1;
		}else if(strcmp(tokens[2],"=")){
			addManagerAlias(managers,TMAIL,tokens[1]);//variable type in first position
			return 1;
		}
	}else if(nbtokens>=4){//new object
		if(!strcmp(tokens[2],"=")){
			if(!strcasecmp(tokens[4],"CreateObject")){
				addManagerObject(managers,TMAIL,tokens[1]);
				return 1;
			}else if(!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TMAIL,tokens[1]);
				return 1;
			}
		}else if(!strcmp(tokens[1],"=")){
			if(!strcasecmp(tokens[3],"CreateObject")){
				addManagerObject(managers,TMAIL,tokens[0]);
				return 1;
			}else if(!strcasecmp(tokens[2],"CreateObject")){
				addManagerObject(managers,TMAIL,tokens[0]);
				return 1;
			}
		}
	}
	return 0;
}

int extractManagers(struct MANAG_ENTRY * managers, struct LINE * line){
	int found;
	//Evaluating expression
	found = extractFileSystemObject(managers,line);
	if(!found) found = extractShellObject(managers,line);
	if(!found) found = extractNetworkObject(managers,line);
	if(!found) found = extractMailObject(managers,line);
	if(!found){//Unknown manager (learned during dynamic analysis)
		char * createfound = strcasestr(line->line,OBJECT_CREATION);
		if(createfound==NULL) createfound = strcasestr(line->line,OBJECT_CREATION2);
		if(createfound){
			char * tokens = (char *) calloc(TOKENMAXNB*TOKENSIZE,sizeof(char));
			int i, nbtokens = decomposeLine(line->line,tokens,TOKENMAXNB,TOKENSIZE);
			for(i = 0; i<nbtokens; i++){
				if(((char *)ACCESS(tokens,i))[0]=='='
				&& ((char *)ACCESS(tokens,i+2))[0]!='"'){ 
					addManagerObject(managers,0,ACCESS(tokens,i-1));
					//line->type = MANAGER;
					found = 1;
				}
			}
		}
	}
	return found;
}

int parseVariables(struct MANAG_ENTRY * managers, struct TYPING * types,
				   struct LINE * line, char * variables [NAME_MAX_LENGTH]){
	int i, nbtokens, nbvars = 0;
	char tokens[20][NAME_MAX_LENGTH];
	char type[NAME_MAX_LENGTH];
	char affectation[NAME_MAX_LENGTH];
	
	nbtokens = decomposeLine(&(line->line[3]),(char*)tokens,20,NAME_MAX_LENGTH);
	for(i=0;i<nbtokens;i++){
		if(tokens[i][0]=='\''){break;} //Comment encountered
		if(!strcasecmp(tokens[i],"as")){//Skip types
			i++;
			//If composed type
			strcpy_s(type,NAME_MAX_LENGTH,".");
			strcat_s(type,NAME_MAX_LENGTH,tokens[i]);
			if(strcasestr(line->line,type)){i++;}
			continue;
		}
		if(tokens[i][0]=='='){//Affectation
			int affobj;
			struct LINE affectdecl;
			char * affectstr = strcasestr(line->line,tokens[i+1]);
			//May declare a manager
			if(affectstr){
				sprintf_s(affectdecl.line,LINE_LENGTH,"%s = ",variables[nbvars-1]);
				strcat_s(affectdecl.line,LINE_LENGTH,affectstr);
				extractManagers(managers,&affectdecl);
			}
			//Store affected value
			processExpression(NULL,NULL,types,0,line,i+2,0,affectation,NULL);
			affobj = isKnownObject(types,affectation);			
			//Otherwise simple value
			if(affobj==-1){
				affobj = addNewObject(types,affectation,0);
			}
			addObjectAlias(types,affobj,variables[nbvars-1]);
			break;
		}
		variables[nbvars] = (char *)calloc(NAME_MAX_LENGTH,sizeof(char));
		strcpy_s(variables[nbvars],NAME_MAX_LENGTH,tokens[i]);
		nbvars++;
	}
	return nbvars;
}





void localizeFuncAndProc(struct SCRIPT * script, struct TYPING * types, FILE * scriptf){
	char line[LINE_LENGTH];
	int codepos;
	int lgth;

	rewind(scriptf);
	while(!feof(scriptf)){
		codepos = ftell(scriptf);
		if(feof(scriptf)) return;
		fgetAlignedLine(line,LINE_LENGTH-2,scriptf);
		//Ignore too important/short lines
		lgth = (int)strlen(line);
		if(lgth>LINE_LENGTH-6) continue;
		if(lgth<=1) continue;
		//Ignore comments and markup lines
		if(line[0]=='\'' || line[0]=='<' || 
			line[0] == 13 ||line[0] == 10){
			continue;
		}
		//Skip declared functions from lib
		if(strcasestr(line,"Declare")) continue;
		//Skip line containing string (avoid function token in strings)
		if(line[0]=='\"'){
			continue;
		}	
		if(strcasestr(line,"end sub")) continue;
		if(strcasestr(line,"end function")) continue;
		fseek(scriptf,codepos,SEEK_SET);
		
		if(fscanf(scriptf,"%s",line)){
			if(!strcasecmp(line,"Function")){
				addFunction(script,types,scriptf);
			}else if(!strcasecmp(line,"Sub")){
				addProcedure(script,types,scriptf);
			}
			line[0]=0;
		}//if

	}//while
}

void addFunction(struct SCRIPT * script, struct TYPING * types, FILE * scriptf){
	int ind; int nbarg = 0, lines = 0; 
	char c; char line[LINE_LENGTH];

	//Increase function number
	ind = script->nbfunc;
	script->nbfunc++;
	//Store begin position
	script->functionslist[ind].begin = ftell(scriptf) - (unsigned long)strlen("Function");
	//Parse function name (until '(' is encountered)
	c = parseString(scriptf,script->functionslist[ind].name);
	//Parse arguments
	if(c=='('){ //if arguments
		while(1){
			script->functionslist[ind].arguments[nbarg] = 
					(char *)calloc(NAME_MAX_LENGTH,sizeof(char));
			c = parseString(scriptf,script->functionslist[ind].arguments[nbarg]);
			if(strcasestr(script->functionslist[ind].arguments[nbarg],"byval")){
				strcpy_s(script->functionslist[ind].arguments[nbarg],
					NAME_MAX_LENGTH, &script->functionslist[ind].arguments[nbarg][5]);
			}
			if(strlen(script->functionslist[ind].arguments[nbarg])) nbarg++;
			if(c == ')'){ break;}
		}//while
	}//enf if arguments
	script->functionslist[ind].nbarg = nbarg;

	//Calculate number of lines
	script->functionslist[ind].codepos = ftell(scriptf);
	while(1){
		fgetAlignedLine(line,LINE_LENGTH-2,scriptf);
		//End of function body
		if(!strncasecmp(line,"End Function",12)) break;
		if(strlen(line)>1) lines++;
	}//while
	//Store end position
	script->functionslist[ind].end = ftell(scriptf)-1;
	script->functionslist[ind].nblines = lines;
	script->functionslist[ind].code = 
		(struct LINE *)calloc(1,(lines+(lines/2)+10)*sizeof(struct LINE));
}

void addProcedure(struct SCRIPT * script, struct TYPING * types, FILE * scriptf){
	int ind; int nbarg = 0, lines = 0;
	char c; char line[LINE_LENGTH];
	
	//Increase procedure number
	ind = script->nbproc;
	script->nbproc++;
	//Store begin position
	script->procedureslist[ind].begin = ftell(scriptf) - (unsigned long)strlen("Sub");
	//Parse procedure name (until '(' is encountered)
	c = parseString(scriptf,script->procedureslist[ind].name);
	//Parse arguments
	if(c=='('){ //if arguments
		while(1){
			script->procedureslist[ind].arguments[nbarg] = 
					(char *)calloc(NAME_MAX_LENGTH,sizeof(char));
			c = parseString(scriptf,script->procedureslist[ind].arguments[nbarg]);
			if(strcasestr(script->procedureslist[ind].arguments[nbarg],"byval")){
				strcpy_s(script->procedureslist[ind].arguments[nbarg],
					NAME_MAX_LENGTH,&script->procedureslist[ind].arguments[nbarg][5]);
			}
			if(strlen(script->procedureslist[ind].arguments[nbarg])) nbarg++;
			if(c == ')') break;
		}//while
	}//end if arguments
	script->procedureslist[ind].nbarg = nbarg;
	
	//Calculate number of lines
	script->procedureslist[ind].codepos = ftell(scriptf);
	while(1){
		fgetAlignedLine(line,LINE_LENGTH-2,scriptf);
		//End of procedure body
		if(!strncasecmp(line,"End Sub",7)) break;
		if(strlen(line)>1) lines++;
	}//while
	//Store end position
	script->procedureslist[ind].end = ftell(scriptf)-1;
	script->procedureslist[ind].nblines = lines;
	script->procedureslist[ind].code = 
		(struct LINE *)calloc(1,(lines+(lines/2)+10)*sizeof(struct LINE));
}

void analyzeMain(struct SCRIPT * script, struct TYPING * types, FILE * scriptf){
	char line[LINE_LENGTH];
	int insidewith = 0; char with[NAME_MAX_LENGTH];
	int position, i, j; int nbvar = 0, nblines = 0;
	int strembedded =0;  
	long rew; int incomment = 0;
	rewind(scriptf);
	//Calculate number of lines
	while(!feof(scriptf)){
		line[0]=0;
		fgetAlignedLine(line,LINE_LENGTH-2,scriptf);
		position = ftell(scriptf)-2; //End of line
		//Must be outside of any procedure and function
		if(insideFunction(script,position)||
			insideProcedure(script,position)) continue; //otherwise skip line
		if(strlen(line)>1){nblines++;}
	}//while
	script->nblines = nblines;
	script->code = 
		(struct LINE *)calloc(1,(nblines+(nblines/2)+50)*sizeof(struct LINE));
	//printf("nb lines attendu %d\n",nblines);

	printf("[+] Begin normalized main body\n");
	//Parse main body
	rewind(scriptf);
	for(i=0;i<script->nblines;){
		if(feof(scriptf)) return;
		fgetAlignedLine(script->code[i].line,LINE_LENGTH-2,scriptf);
		position = ftell(scriptf)-2;//end of line
		if(strlen(script->code[i].line)<2) continue;

		//Must be outside of any procedure and function
		if(insideFunction(script,position)||
			insideProcedure(script,position)) continue; //otherwise skip line
		
		//Checks for code embedded in string
		if(script->code[i].line[0]=='\"'){
			strembedded = 1;
			script->code[i].line[0] = ' ';
		}	

		//Comment
		if(!strncasecmp(script->code[i].line,"'",1)||
			!strncasecmp(script->code[i].line,"rem ",4)){
			script->code[i].type = COMMENT;
			//printLine(&script->code[i]);
			i++;
			continue;
		}

		//Markup
		if(!strncasecmp(script->code[i].line,"<",1)){
			script->code[i].type = MARKUP;
			//printLine(&script->code[i]);
			i++;
			continue;
		}

		//Function declaration
		if(strcasestr(script->code[i].line,"declare")
			&&strcasestr(script->code[i].line,"function")){
			script->code[i].type = DECLARATION;
			if(strembedded){strembedded = 0;script->code[i].line[0] = '\"';}
			//printLine(&script->code[i]);
			i++;
			continue;
		}
		
		//Detect instruction pipe
		incomment = 0;
		for(j=0;j<strlen(script->code[i].line);j++){
			if(script->code[i].line[j]=='"') incomment ^= 1;
			if(!incomment&&script->code[i].line[j]==':'){
				rew = ftell(scriptf)-(strlen(&script->code[i].line[j])-1);
				fseek(scriptf,rew,SEEK_SET);
				script->code[i].line[j] = 0;
				script->nblines++;
			}
		}	

		//If line contains code, normalize it
		normalizeLine(&script->code[i]);

		//With structure
		if(strcasestr(script->code[i].line,"End With")){
			insidewith=0;
			script->code[i].type = DECLARATION;
			//printLine(&script->code[i]);
			i++;
			continue;
		}
		if(!strncasecmp(script->code[i].line,"With",4)){
			insidewith = 1;
			script->code[i].type = DECLARATION;
			sscanf_s(&script->code[i].line[4],"%s",with);
			
			//printLine(&script->code[i]);
			i++;
			continue;
		}
		if(insidewith&&line,script->code[i].line[0]=='.'){
			strcpy_s(line,LINE_LENGTH,with);
			strcat_s(line,LINE_LENGTH,script->code[i].line);
			strcpy_s(script->code[i].line,LINE_LENGTH,line);
		}

		//Variable declaration
		if(!strncasecmp(script->code[i].line,"Dim",3)||
			!strncasecmp(script->code[i].line," Dim",4)){
			nbvar += parseVariables(&script->managers,types,
									&script->code[i],&(script->variables[nbvar]));
			script->code[i].type = DECLARATION;
			if(strembedded){strembedded = 0;script->code[i].line[0] = '\"';}
			//printLine(&script->code[i]);
			i++;
			continue;
		}

		//Detect string ciphering
		if(!script->strciphered){ 
			if(detectStringCiphering(script,types,MAINLEVEL,i,scriptf)){
				//Update already parsed lines
				for(j=0;j<i;j++){
					char * found;
					if(script->code[j].type==COMMENT||
						script->code[j].type==MARKUP) continue;
					found = strstr(script->code[j].line,
							script->functionslist[script->cipherfunction].name);
					if(found){
						decipherString(script,found,
							script->functionslist[script->cipherfunction].nbarg);
						normalizeLine(&script->code[j]);
						extractManagers(&script->managers,&script->code[j]);
					}
				}//for
			}
		}
		//Deciphering
		if(script->strciphered){
			char * found = strstr(script->code[i].line,
							script->functionslist[script->cipherfunction].name);
			if(found){
				decipherString(script,found,
					script->functionslist[script->cipherfunction].nbarg);
				normalizeLine(&script->code[i]);
			}
		}


		//Managers extraction
		extractManagers(&script->managers,&script->code[i]);

		//Checks for code embedded in string
		if(strembedded){strembedded = 0;script->code[i].line[0] = '\"';}

		//printLine(&script->code[i]);
		i++;
	}
	printf("[+] End normalized main body\n");
	script->nbvar = nbvar;
}

void parseFunction(int findex, struct SCRIPT * script, struct TYPING * types, FILE * scriptf){
	int i, j; int nbvar = 0; 
	int insidewith = 0; 
	char with[NAME_MAX_LENGTH]; char line[LINE_LENGTH];
	int strembedded = 0;
	int splitline = 0;

	printf("[+] Begin normalized function body: %s\n",
							script->functionslist[findex].name);
	//Parse function body
	fseek(scriptf,script->functionslist[findex].codepos,SEEK_SET);
	for(i=0;i<script->functionslist[findex].nblines;){
		fgetAlignedLine(script->functionslist[findex].code[i].line,LINE_LENGTH-2,scriptf);
		if(strlen(script->functionslist[findex].code[i].line)<2) continue; 

		//Checks for code embedded in string
		if(script->functionslist[findex].code[i].line[0]=='\"'){
			strembedded = 1;
			script->functionslist[findex].code[i].line[0] = ' ';
		}

		//Comment
		if(!strncasecmp(script->functionslist[findex].code[i].line,"'",1)||
			!strncasecmp(script->functionslist[findex].code[i].line,"rem ",4)){
			script->functionslist[findex].code[i].type = COMMENT;
			//printLine(&script->functionslist[ind].code[i]);
			i++;
			continue;
		}

		//Markup
		if(!strncasecmp(script->functionslist[findex].code[i].line,"<",1)){
			script->functionslist[findex].code[i].type = MARKUP;
			//printLine(&script->functionslist[ind].code[i]);
			i++;
			continue;
		}

		//Function declaration
		if(strcasestr(script->functionslist[findex].code[i].line,"declare")
			&&strcasestr(script->functionslist[findex].code[i].line,"function")){
			script->functionslist[findex].code[i].type = DECLARATION;
			//printLine(&script->functionslist[findex].code[i]);
			i++;
			continue;
		}

		//If line contains code, normalize it
		normalizeLine(&script->functionslist[findex].code[i]);

		//With structure
		if(strcasestr(script->functionslist[findex].code[i].line,"End With")){
			insidewith=0;
			script->functionslist[findex].code[i].type = DECLARATION;
			//printLine(&script->functionslist[findex].code[i]);
			i++;
			continue;
		}
		if(!strncasecmp(script->functionslist[findex].code[i].line,"With",4)){
			insidewith = 1;
			script->functionslist[findex].code[i].type = DECLARATION;
			sscanf_s(&script->functionslist[findex].code[i].line[4],"%s",with);
			//printLine(&script->functionslist[findex].code[i]);
			i++;
			continue;
		}
		if(insidewith&&line,script->functionslist[findex].code[i].line[0]=='.'){
			strcpy_s(line,LINE_LENGTH,with);
			strcat_s(line,LINE_LENGTH,script->functionslist[findex].code[i].line);
			strcpy_s(script->functionslist[findex].code[i].line,LINE_LENGTH,line);
		}

		//Variable declaration
		if(!strncasecmp(script->functionslist[findex].code[i].line,"Dim",3)){
			nbvar += parseVariables(&script->functionslist[findex].managers,
									types, &script->functionslist[findex].code[i], 
									&(script->functionslist[findex].variables[nbvar]));
			script->functionslist[findex].code[i].type = DECLARATION;
			//printLine(&script->functionslist[findex].code[i]);
			i++;
			continue;
		}

		//Detect string ciphering
		if(!script->strciphered){ 
			if(detectStringCiphering(script,types,FUNCLEVEL|findex,i,scriptf)){
				//Update already parsed lines
				for(j=0;j<i;j++){
					char * found;
					if(script->functionslist[findex].code[j].type==COMMENT||
						script->functionslist[findex].code[j].type==MARKUP) continue;
					found = strstr(script->functionslist[findex].code[j].line,
							script->functionslist[script->cipherfunction].name);
					if(found){
						decipherString(script,found,
							script->functionslist[script->cipherfunction].nbarg);
						normalizeLine(&script->functionslist[findex].code[j]);
						extractManagers(&script->functionslist[findex].managers,
								        &script->functionslist[findex].code[j]);
					}
				}//for
			}
		}
		//Deciphering
		if(script->strciphered){
			char * found = strstr(script->functionslist[findex].code[i].line,
							script->functionslist[script->cipherfunction].name);
			if(found){
				decipherString(script,found,
					script->functionslist[script->cipherfunction].nbarg);
				normalizeLine(&script->functionslist[findex].code[i]);
			}
		}

		//Managers extraction
		extractManagers(&script->functionslist[findex].managers,
			            &script->functionslist[findex].code[i]);
		extractManagers(&script->managers,&script->functionslist[findex].code[i]);

		//Checks for code embedded in string
		if(strembedded){
			strembedded = 0;
			script->functionslist[findex].code[i].line[0] = '\"';
		}

		//printLine(&script->functionslist[findex].code[i]);
		i++;
	}//for
	printf("[+] End normalized function body: %s\n",
						script->functionslist[findex].name);
	script->functionslist[findex].nbvar = nbvar;
	//Skip end function
	//fgets(line,LINE_LENGTH-2,scriptf);
	//printFunction(script->functionslist[ind]);
}

void parseProcedure(int pindex, struct SCRIPT * script, struct TYPING * types, FILE * scriptf){
	int i, j; int nbvar = 0;
	int insidewith = 0; 
	char with[NAME_MAX_LENGTH]; char line[LINE_LENGTH];
	int strembedded = 0;
	


	printf("[+] Begin normalized procedure body: %s\n",
							script->procedureslist[pindex].name);
	//Parse procedure body
	fseek(scriptf,script->procedureslist[pindex].codepos,SEEK_SET);
	for(i=0;i<script->procedureslist[pindex].nblines;){
		fgetAlignedLine(script->procedureslist[pindex].code[i].line,LINE_LENGTH-2,scriptf);
		if(strlen(script->procedureslist[pindex].code[i].line)<2) continue;

		//Checks for code embedded in string
		if(script->procedureslist[pindex].code[i].line[0]=='\"'){
			strembedded = 1;
			script->procedureslist[pindex].code[i].line[0] = ' ';
		}

		//Comment
		if(!strncasecmp(script->procedureslist[pindex].code[i].line,"'",1)||
			!strncasecmp(script->procedureslist[pindex].code[i].line,"rem ",4)){
			script->procedureslist[pindex].code[i].type = COMMENT;
			//printLine(&script->procedureslist[pindex].code[i]);
			i++;
			continue;
		}

		//Markup
		if(!strncasecmp(script->procedureslist[pindex].code[i].line,"<",1)){
			script->procedureslist[pindex].code[i].type = MARKUP;
			//printLine(&script->procedureslist[pindex].code[i]);
			i++;
			continue;
		}

		//Function declaration
		if(strcasestr(script->procedureslist[pindex].code[i].line,"declare")
			&&strcasestr(script->procedureslist[pindex].code[i].line,"function")){
			script->procedureslist[pindex].code[i].type = DECLARATION;
			//printLine(&script->procedureslist[pindex].code[i]);
			i++;
			continue;
		}

		//If line contains code, normalize it
		normalizeLine(&script->procedureslist[pindex].code[i]);

		//With structure
		if(strcasestr(script->procedureslist[pindex].code[i].line,"End With")){
			insidewith=0;
			script->procedureslist[pindex].code[i].type = DECLARATION;
			//printLine(&script->procedureslist[pindex].code[i]);
			i++;
			continue;
		}
		if(!strncasecmp(script->procedureslist[pindex].code[i].line,"With",4)){
			insidewith = 1;
			script->procedureslist[pindex].code[i].type = DECLARATION;
			sscanf_s(&script->procedureslist[pindex].code[i].line[4],"%s",with);
			//printLine(&script->procedureslist[pindex].code[i]);
			i++;
			continue;
		}
		if(insidewith&&line,script->procedureslist[pindex].code[i].line[0]=='.'){
			strcpy_s(line,LINE_LENGTH,with);
			strcat_s(line,LINE_LENGTH,script->procedureslist[pindex].code[i].line);
			strcpy_s(script->procedureslist[pindex].code[i].line,LINE_LENGTH,line);
		}

		//Variable declaration
		if(!strncasecmp(script->procedureslist[pindex].code[i].line,"Dim",3)){
			nbvar += parseVariables(&script->procedureslist[pindex].managers,
									types, &script->procedureslist[pindex].code[i], 
									&(script->procedureslist[pindex].variables[nbvar]));
			script->procedureslist[pindex].code[i].type = DECLARATION;
			//printLine(&script->procedureslist[pindex].code[i]);
			i++;
			continue;
		}

		//Detect string ciphering
		if(!script->strciphered){ 
			if(detectStringCiphering(script,types,PROCLEVEL|pindex,i,scriptf)){
				//Update already parsed lines
				for(j=0;j<i;j++){
					char * found;
					if(script->procedureslist[pindex].code[j].type==COMMENT||
						script->procedureslist[pindex].code[j].type==MARKUP) continue;
					found = strstr(script->procedureslist[pindex].code[j].line,
							script->functionslist[script->cipherfunction].name);
					if(found){
						decipherString(script,found,
							script->functionslist[script->cipherfunction].nbarg);
						normalizeLine(&script->procedureslist[pindex].code[j]);
						extractManagers(&script->procedureslist[pindex].managers,
								        &script->procedureslist[pindex].code[j]);
					}
				}//for
			}
		}
		//Deciphering
		if(script->strciphered){
			char * found = strstr(script->procedureslist[pindex].code[i].line,
							script->functionslist[script->cipherfunction].name);
			if(found){
				decipherString(script,found,
					script->functionslist[script->cipherfunction].nbarg);
				normalizeLine(&script->procedureslist[pindex].code[i]);
			}
		}

		//Managers extraction
		extractManagers(&script->procedureslist[pindex].managers,
					    &script->procedureslist[pindex].code[i]);
		extractManagers(&script->managers,&script->procedureslist[pindex].code[i]);

		//Checks for code embedded in string
		if(strembedded){
			strembedded = 0;
			script->procedureslist[pindex].code[i].line[0] = '\"';
		}
		
		//printLine(&script->procedureslist[pindex].code[i]);
		i++;
	}//for
	printf("[+] End normalized procedure body: %s\n",
							script->procedureslist[pindex].name);
	script->procedureslist[pindex].nbvar = nbvar;
	//Skip end procedure
	//fgets(line,LINE_LENGTH-2,scriptf);
	//printProcedure(script->procedureslist[ind]);
}